{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "id": "zrxOdPebTco5"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import tensorflow as tf\n",
        "import tensorflow.keras as K\n",
        "import matplotlib.pyplot as plt"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "LiXC6JXETco7"
      },
      "outputs": [],
      "source": [
        "np.random.seed(11)\n",
        "tf.random.set_seed(11)\n",
        "batch_size = 256\n",
        "max_epochs = 50\n",
        "learning_rate = 1e-3\n",
        "momentum = 8e-1\n",
        "hidden_dim = 128\n",
        "original_dim = 784"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "eMUF0vLlTco9",
        "outputId": "0df8a955-6219-448e-ce53-eaf33e5b8fa7"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz\n",
            "11493376/11490434 [==============================] - 0s 0us/step\n",
            "11501568/11490434 [==============================] - 0s 0us/step\n"
          ]
        }
      ],
      "source": [
        "(x_train, _), (x_test, _) = K.datasets.mnist.load_data()\n",
        "\n",
        "x_train = x_train / 255.\n",
        "x_test = x_test / 255.\n",
        "\n",
        "x_train = x_train.astype(np.float32)\n",
        "x_test = x_test.astype(np.float32)\n",
        "\n",
        "x_train = np.reshape(x_train, (x_train.shape[0], 784))\n",
        "x_test = np.reshape(x_test, (x_test.shape[0], 784))\n",
        "\n",
        "training_dataset = tf.data.Dataset.from_tensor_slices(x_train).batch(batch_size)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "id": "mXFx2bMUTco-"
      },
      "outputs": [],
      "source": [
        "\n",
        "class Encoder(K.layers.Layer):\n",
        "    def __init__(self, hidden_dim):\n",
        "        super(Encoder, self).__init__()\n",
        "        self.hidden_layer = K.layers.Dense(units=hidden_dim, activation=tf.nn.relu)\n",
        "        \n",
        "    \n",
        "    def call(self, input_features):\n",
        "        activation = self.hidden_layer(input_features)\n",
        "        return activation"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "id": "gGKJlc_bTco_"
      },
      "outputs": [],
      "source": [
        "\n",
        "class Decoder(K.layers.Layer):\n",
        "    def __init__(self, hidden_dim, original_dim):\n",
        "        super(Decoder, self).__init__()\n",
        "        self.output_layer = K.layers.Dense(units=original_dim, activation=tf.nn.relu)\n",
        "  \n",
        "    def call(self, encoded):\n",
        "        activation = self.output_layer(encoded)\n",
        "        return activation "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "id": "xCWqWjPcTcpA"
      },
      "outputs": [],
      "source": [
        "class Autoencoder(K.Model):\n",
        "    def __init__(self, hidden_dim, original_dim):\n",
        "        super(Autoencoder, self).__init__()\n",
        "        self.loss = []\n",
        "        self.encoder = Encoder(hidden_dim=hidden_dim)\n",
        "        self.decoder = Decoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
        "\n",
        "    def call(self, input_features):\n",
        "        encoded = self.encoder(input_features)\n",
        "        reconstructed = self.decoder(encoded)\n",
        "        return reconstructed"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {
        "id": "Nhy4ZPvFTcpA"
      },
      "outputs": [],
      "source": [
        "autoencoder = Autoencoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
        "opt = tf.optimizers.SGD(learning_rate=learning_rate, momentum=momentum)\n",
        "def loss(preds, real):\n",
        "    return tf.reduce_mean(tf.square(tf.subtract(preds, real)))\n",
        "\n",
        "def train(loss, model, opt, original):\n",
        "    with tf.GradientTape() as tape:\n",
        "        preds = model(original)\n",
        "        reconstruction_error = loss(preds, original)\n",
        "    gradients = tape.gradient(reconstruction_error, model.trainable_variables)\n",
        "    gradient_variables = zip(gradients, model.trainable_variables)\n",
        "    opt.apply_gradients(gradient_variables)\n",
        "  \n",
        "    return reconstruction_error"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "id": "x533YAFWTcpC"
      },
      "outputs": [],
      "source": [
        "def train_loop(model, opt, loss, dataset, epochs=20):\n",
        "    for epoch in range(epochs):\n",
        "        epoch_loss = 0\n",
        "        for step, batch_features in enumerate(dataset):\n",
        "            loss_values = train(loss, model, opt, batch_features)\n",
        "            epoch_loss += loss_values\n",
        "        model.loss.append(epoch_loss)\n",
        "        print('Epoch {}/{}. Loss: {}'.format(epoch + 1, epochs, epoch_loss.numpy()))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "OmJsuqBKTcpD",
        "outputId": "82ccc988-d425-4e35-825a-02433511372b"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Epoch 1/50. Loss: 5.158795356750488\n",
            "Epoch 2/50. Loss: 3.0751724243164062\n",
            "Epoch 3/50. Loss: 2.9574835300445557\n",
            "Epoch 4/50. Loss: 2.9055161476135254\n",
            "Epoch 5/50. Loss: 2.87841534614563\n",
            "Epoch 6/50. Loss: 2.8393068313598633\n",
            "Epoch 7/50. Loss: 2.826066493988037\n",
            "Epoch 8/50. Loss: 2.821895122528076\n",
            "Epoch 9/50. Loss: 2.852160930633545\n",
            "Epoch 10/50. Loss: 2.807100772857666\n",
            "Epoch 11/50. Loss: 2.8118016719818115\n",
            "Epoch 12/50. Loss: 2.811497688293457\n",
            "Epoch 13/50. Loss: 2.811824321746826\n",
            "Epoch 14/50. Loss: 2.8174896240234375\n",
            "Epoch 15/50. Loss: 2.7967369556427\n",
            "Epoch 16/50. Loss: 2.805511951446533\n",
            "Epoch 17/50. Loss: 2.7915103435516357\n",
            "Epoch 18/50. Loss: 2.8029065132141113\n",
            "Epoch 19/50. Loss: 2.7935240268707275\n",
            "Epoch 20/50. Loss: 2.794471263885498\n",
            "Epoch 21/50. Loss: 2.793509006500244\n",
            "Epoch 22/50. Loss: 2.8106918334960938\n",
            "Epoch 23/50. Loss: 2.795088052749634\n",
            "Epoch 24/50. Loss: 2.811030626296997\n",
            "Epoch 25/50. Loss: 2.7980599403381348\n",
            "Epoch 26/50. Loss: 2.7909412384033203\n",
            "Epoch 27/50. Loss: 2.8127174377441406\n",
            "Epoch 28/50. Loss: 2.8081088066101074\n",
            "Epoch 29/50. Loss: 2.770834445953369\n",
            "Epoch 30/50. Loss: 2.8026235103607178\n",
            "Epoch 31/50. Loss: 2.801159143447876\n",
            "Epoch 32/50. Loss: 2.781203508377075\n",
            "Epoch 33/50. Loss: 2.850271463394165\n",
            "Epoch 34/50. Loss: 2.81256103515625\n",
            "Epoch 35/50. Loss: 2.8006041049957275\n",
            "Epoch 36/50. Loss: 2.7784485816955566\n",
            "Epoch 37/50. Loss: 2.7928662300109863\n",
            "Epoch 38/50. Loss: 2.812906503677368\n",
            "Epoch 39/50. Loss: 2.7930636405944824\n",
            "Epoch 40/50. Loss: 2.8065478801727295\n",
            "Epoch 41/50. Loss: 2.8079276084899902\n",
            "Epoch 42/50. Loss: 2.805914878845215\n",
            "Epoch 43/50. Loss: 2.7804012298583984\n",
            "Epoch 44/50. Loss: 2.7939512729644775\n",
            "Epoch 45/50. Loss: 2.803565740585327\n",
            "Epoch 46/50. Loss: 2.7910079956054688\n",
            "Epoch 47/50. Loss: 2.803776264190674\n",
            "Epoch 48/50. Loss: 2.790198802947998\n",
            "Epoch 49/50. Loss: 2.786236047744751\n",
            "Epoch 50/50. Loss: 2.7854647636413574\n"
          ]
        }
      ],
      "source": [
        "autoencoder = Autoencoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
        "opt = tf.keras.optimizers.Adam(learning_rate=1e-2)\n",
        "\n",
        "train_loop(autoencoder, opt, loss, training_dataset, epochs=max_epochs)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 279
        },
        "id": "7Wav8gkiTcpE",
        "outputId": "86b79d63-9b38-4cd4-b022-ac25b7ea1b01"
      },
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light"
          }
        }
      ],
      "source": [
        "\n",
        "plt.plot(range(max_epochs), autoencoder.loss)\n",
        "plt.xlabel('Epochs')\n",
        "plt.ylabel('Loss')\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 248
        },
        "id": "AkKmKG1VTcpF",
        "outputId": "6f1bfddf-c8ae-4768-c556-d6bd4575a5bb"
      },
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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12XLlmkc7jy94oorNPbrS+3evVtjv40uIvftt986x23bttX4jjvu0NjWwxBx623Ye8q5c+c682zdNr99cJMmTTS298bjxo1z5m3bti30f0CCs9/TbI1SEffzyD/HUlNTNbb3Pv48+96Fuw/Knz+/xn7rdvv6GzdujOj1ktXKlSudY1tbZsSIEc6YvX+tUaOGxn4dP3sNtfeo9hosIlKmTBmN/Zbf9hyzNflGjhzpzJs2bZrkNHbaAAAAAAAABBAPbQAAAAAAAAIo16RHRZvddudvo7Jb0IcPHx63NSW6+vXra2zTM95++21n3l//+tds/65wKQWIj3z58mlszze/rfesWbPitqZkYtMJ/a26dizSlsN2W2q4VtN+a9NrrrlG48svv1xj29JWxN3y77cDz0qb+dxq/fr1zrFNf7BbhkVEunfvrnHXrl013rp1qzPPbksuVaqUxn5qjb1u2vQMEZGOHTtqbFM8Fi1adPZ/BKLObsu311M/ddy2JfWvtYidDRs2ZBhnVdWqVTW26Ygi7nb+cNdihOenuE2aNEnjChUqaGxTK0RElixZovHo0aM1/vzzz51533//vcatWrVyxlq0aKGxTf+w/7uIWy4g2dh7d7+0gU2v9ktc2H9Dm4Jz6NAhZ55NZ7L3LX7JBstPj7LrsOlx7733XsjXSFb+fWi4tPfspvb27dvXObbpdP7fweLFizUeNmyYxkFIh/Kx0wYAAAAAACCAeGgDAAAAAAAQQDy0AQAAAAAACKCkrWlz/fXXa2zb0Iq49RSmT58etzUlGlu/QsTN27VtYgcPHhz1302ed87r1KmTxpdeeqnGNs9bRGTFihVxW1MysW1ibR0TEZG9e/dqXLhw4Wz/LtsS015bRUTuv/9+jW3r982bNzvz1qxZozFtpH9h69H4rWftsa3N5rfWtNdem7vv176xNQTseyritrm1886cORP+PwBR0b59e41te2m/bo3fxhi5g/28FBHp16+fxtu3b3fGVq9erbFfnwFZZ+tZ2GujrVsi4tbbsJ9b4dg6YCLuedq6dWuN/Vpi9ufs+55s/Fbotm2z//6ULFkyw9ivVWM/F20NKX+evVc5cuSIM+bXO/qZX5fPP0b02ftLW4NPxP07mD9/vjM2YcIEjf06V0HDThsAAAAAAIAA4qENAAAAAABAACVNetRtt93mHN97770a+63k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\n",
            "text/plain": [
              "<Figure size 1440x288 with 20 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light"
          }
        }
      ],
      "source": [
        "number = 10  # how many digits we will display\n",
        "plt.figure(figsize=(20, 4))\n",
        "for index in range(number):\n",
        "    # display original\n",
        "    ax = plt.subplot(2, number, index + 1)\n",
        "    plt.imshow(x_test[index].reshape(28, 28), cmap='gray')\n",
        "    ax.get_xaxis().set_visible(False)\n",
        "    ax.get_yaxis().set_visible(False)\n",
        "\n",
        "    # display reconstruction\n",
        "    ax = plt.subplot(2, number, index + 1 + number)\n",
        "    plt.imshow(autoencoder(x_test)[index].numpy().reshape(28, 28), cmap='gray')\n",
        "    ax.get_xaxis().set_visible(False)\n",
        "    ax.get_yaxis().set_visible(False)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "id": "S_K_sa4TTcpH"
      },
      "outputs": [],
      "source": [
        ""
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    },
    "colab": {
      "name": "VanillaAutoEncoder.ipynb",
      "provenance": []
    },
    "accelerator": "GPU"
  },
  "nbformat": 4,
  "nbformat_minor": 0
}